#ifndef DATACACHE_H
#define DATACACHE_H

#include <QThread>
#include <QReadWriteLock>
#include <QMultiHash>
#include <QSharedPointer>
#include <QQueue>
#include "point.h"
#include "mapelement.h"
#include "node.h"
#include "junction.h"
#include "way.h"
#include "building.h"
#include "block.h"
#include "utils.h"

class DataCache : protected QThread
{
public:
    enum CachePolicy
    {
        DEFAULT = 0x01,
        MINIMUM_MEMORY = 0x01,
        MINIMUM_CALC = 0x02
    };

    class UpdateParameters
    {
    public:
        Point center;
        double angleRadius;
        quint32 detalization;
        explicit UpdateParameters(const Point & center = Point(), double angleRadius = 0, quint32 detalization = MapElement::NONE);
    };

    class CacheSettings
    {
    public:
        CachePolicy policy;
        double blockWidth;
        double blockHeight;
    };

private:
    Point lastCenter;
    double lastAngleRadius;
    quint32 lastDetalization;
    double radiusBufRatio;
    QLinkedList<MapElement::Type> elementTypes;
    QHash<MapElement::Type, CacheSettings> cacheSettings;
    QQueue<UpdateParameters> updateParameters;
    QHash<MapElement::Type, QHash<int, QHash<int, Block<QSharedPointer<MapElement> > *> *> *> elementBlocks;
    QHash<int, QHash<int, Block<QSharedPointer<Way> > *> *> wayBlocks;
    QHash<int, QHash<int, Block<QSharedPointer<Building> > *> *> buildingBlocks;
    bool doStop;
    QReadWriteLock rwLock;
    QReadWriteLock rwUpdateLock;
protected:
    void run();
public:
    DataCache();
    void stop();
    void update(const Point & center, double angleRadius, quint32 detalization);
private:
    double bufRadius(double radius);
    Block<QSharedPointer<MapElement> > * loadBlock(MapElement::Type type, double latitude, double longitude);
    void cleanup(MapElement::Type type, const UpdateParameters & params);
    void load(MapElement::Type type, const UpdateParameters & params);
};

#endif // DATACACHE_H
